﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WMS.Common.JWT
{
    using System.IdentityModel.Tokens.Jwt;
    using System.Security.Claims;
    using System.Text;
    using global::WMS.Model;
    using Microsoft.IdentityModel.Tokens;

    /// <summary>
    /// JWT 帮助类
    /// </summary>
    public static class JwtHelper
    {
        private static readonly JwtSettings _settings = new JwtSettings();

        /// <summary>
        /// 生成 JWT Token
        /// </summary>
        /// <param name="claims">声明集合</param>
        /// <returns>JWT Token字符串</returns>
        public static string GenerateToken(List<Claim> claims)
        {
            return GenerateToken(claims, _settings.ExpireMinutes);
        }

        /// <summary>
        /// 生成 JWT Token
        /// </summary>
        /// <param name="claims">声明集合</param>
        /// <param name="expireMinutes">过期时间（分钟）</param>
        /// <returns>JWT Token字符串</returns>
        public static string GenerateToken(List<Claim> claims, int expireMinutes)
        {
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_settings.SecurityKey));
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

            var token = new JwtSecurityToken(
                issuer: _settings.Issuer,
                audience: _settings.Audience,
                claims: claims,
                expires: DateTime.Now.AddMinutes(expireMinutes),
                signingCredentials: creds);

            return new JwtSecurityTokenHandler().WriteToken(token);
        }

        /// <summary>
        /// 为用户生成 Token
        /// </summary>
        /// <param name="user">用户信息</param>
        /// <returns>JWT Token字符串</returns>
        public static string GenerateUserToken(UserModel user)
        {
            var claims = new List<Claim>
        {
            new Claim(JwtRegisteredClaimNames.Sub, _settings.Issuer),
            new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
            new Claim(JwtRegisteredClaimNames.Iat, DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(), ClaimValueTypes.Integer64),
            new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
            new Claim(ClaimTypes.Name, user.Account),
            new Claim("Account", user.Account),
            new Claim("UserId", user.Id.ToString())
        };

            // 可以添加角色声明
            // if (!string.IsNullOrEmpty(user.Role))
            // {
            //     claims.Add(new Claim(ClaimTypes.Role, user.Role));
            // }

            return GenerateToken(claims);
        }

        /// <summary>
        /// 验证 Token 是否有效
        /// </summary>
        /// <param name="token">JWT Token</param>
        /// <returns>是否有效</returns>
        public static bool ValidateToken(string token)
        {
            try
            {
                var tokenHandler = new JwtSecurityTokenHandler();
                var key = Encoding.UTF8.GetBytes(_settings.SecurityKey);

                tokenHandler.ValidateToken(token, new TokenValidationParameters
                {
                    ValidateIssuer = true,
                    ValidateAudience = true,
                    ValidateLifetime = true,
                    ValidateIssuerSigningKey = true,
                    ValidIssuer = _settings.Issuer,
                    ValidAudience = _settings.Audience,
                    IssuerSigningKey = new SymmetricSecurityKey(key),
                    ClockSkew = TimeSpan.Zero // 消除时间偏移
                }, out SecurityToken validatedToken);

                return true;
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// 从 Token 中获取声明信息
        /// </summary>
        /// <param name="token">JWT Token</param>
        /// <returns>声明集合</returns>
        public static IEnumerable<Claim> GetClaimsFromToken(string token)
        {
            try
            {
                var tokenHandler = new JwtSecurityTokenHandler();
                var jwtToken = tokenHandler.ReadJwtToken(token);
                return jwtToken.Claims;
            }
            catch
            {
                return Enumerable.Empty<Claim>();
            }
        }

        /// <summary>
        /// 从 Token 中获取用户ID
        /// </summary>
        /// <param name="token">JWT Token</param>
        /// <returns>用户ID</returns>
        public static string GetUserIdFromToken(string token)
        {
            var claims = GetClaimsFromToken(token);
            return claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier)?.Value;
        }

        /// <summary>
        /// 从 Token 中获取用户名
        /// </summary>
        /// <param name="token">JWT Token</param>
        /// <returns>用户名</returns>
        public static string GetUserNameFromToken(string token)
        {
            var claims = GetClaimsFromToken(token);
            return claims.FirstOrDefault(c => c.Type == ClaimTypes.Name)?.Value;
        }

        /// <summary>
        /// 获取 Token 过期时间
        /// </summary>
        /// <param name="token">JWT Token</param>
        /// <returns>过期时间</returns>
        public static DateTime? GetExpireTimeFromToken(string token)
        {
            try
            {
                var tokenHandler = new JwtSecurityTokenHandler();
                var jwtToken = tokenHandler.ReadJwtToken(token);
                return jwtToken.ValidTo;
            }
            catch
            {
                return null;
            }
        }

        /// <summary>
        /// 刷新 Token
        /// </summary>
        /// <param name="token">原 Token</param>
        /// <param name="expireMinutes">新的过期时间（分钟）</param>
        /// <returns>新的 Token</returns>
        public static string RefreshToken(string token, int expireMinutes = 0)
        {
            var claims = GetClaimsFromToken(token).ToList();

            // 移除标准声明，保留自定义声明
            claims.RemoveAll(c => c.Type == JwtRegisteredClaimNames.Jti);
            claims.RemoveAll(c => c.Type == JwtRegisteredClaimNames.Iat);
            claims.RemoveAll(c => c.Type == JwtRegisteredClaimNames.Exp);

            if (expireMinutes <= 0)
            {
                expireMinutes = _settings.ExpireMinutes;
            }

            return GenerateToken(claims, expireMinutes);
        }
    }
}
